package ar.edu.uba.fi.jmit.aspecter.monitor.methodTime;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javassist.ClassPool;
import javassist.CtClass;
import ar.edu.uba.fi.jmit.aspecter.AspecterTestCase;
import ar.edu.uba.fi.jmit.aspecter.core.Constants;
import ar.edu.uba.fi.jmit.aspecter.core.MethodDefinition;
import ar.edu.uba.fi.jmit.aspecter.core.ResourceProperties;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.EventPriorityMock;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MockEvent;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.SenderFactoryMock;

public class MethodTimeMethodInterceptorTestCase extends AspecterTestCase {

	public void testMethodTime() {
		SenderFactoryMock.clean();
		MethodDefinition methodDefinition = new MethodDefinition(
				ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget.class,
				"methodTime", 
				new LinkedList<Class<?>>(), 
				void.class);
		
		MethodTimeMethodInterceptor interceptor = new MethodTimeMethodInterceptor("MethodTimeMethodInterceptorTestCase.testMethodTime", methodDefinition);
		
		try {
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MethodTimeTargetObject", getNextClassName());
			ctClazz.instrument(interceptor);
			Class<?> clazz = ctClazz.toClass();
			Object object = clazz.newInstance();
			clazz.getMethod("doSomething").invoke(object);
			List<MockEvent> list = SenderFactoryMock.getSenderInstance().getSendedEvents();
			assertEquals(1, list.size());
			MockEvent event = list.get(0);
			assertEquals("MethodTimeMethodInterceptorTestCase.testMethodTime", event.getData().get(ResourceProperties.getProperty(Constants.EVENT_MONITOR_NAME_KEY)));
			Date eventDate = (Date) event.getData().get(ResourceProperties.getProperty(Constants.EVENT_MONITOR_DATE));
			assertSimilarDates(new Date(), eventDate);
			assertEquals("void_ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget.methodTime()", event.getSource());
			assertEquals(EventPriorityMock.NORMAL, event.getPriority());
			long monitorTimeValue = (Long)event.getData().get(ResourceProperties.getProperty(Constants.METHOD_ELAPSED_TIME));
			long objectTimeValue = (Long)clazz.getMethod("getTargetObjectTime").invoke(object);;
			logger.info("Monitor Time: " + monitorTimeValue + " ms");
			logger.info("Object Time: " + objectTimeValue + " ms");
			assertTrue(objectTimeValue - (objectTimeValue * 0.02) <= monitorTimeValue);
			assertTrue(objectTimeValue + (objectTimeValue * 0.02) >= monitorTimeValue);
			
		} catch (Exception e) {
			fail(e);
		} 
	}
}
